﻿#ifndef _C_JSMANAGER2_H_INCLUDE_
#define _C_JSMANAGER2_H_INCLUDE_

#include "../network/cwebsocketserver.h"
#include "../network/networkframemanager.h"
#include "../common/singleton.h"

#include <QObject>
#include <QTimer>
#include <QVector>
#include <QScriptEngine>
#include <QScriptEngineDebugger>
#include <QFileSystemWatcher>
#include <QHash>

/**
 * @brief The CJsManager2 class 脚本管理类，使用QScriptEngine
 *
 * 注意：脚本文件一定要采用GBK编码，否则读取的将是乱码
 */
class CJsManager2 : public QObject ,
                    public NetworkFrameManager ,
                    public Singleton<CJsManager2>
{
    Q_OBJECT

public:
    explicit CJsManager2(QObject *parent = nullptr);
    ~CJsManager2();

    /// 初始化系统
    bool init_system(QString workingpath,
                     QString regdllpath="",
                     int debugserverport=-1,
                     bool isauotoloadscript=true,
                     bool isStartDebugServer=true,
                     bool isEnableDebugMode=false);
    /// 卸载系统
    void clean_system(void);

    /// 启动调试服务器
    bool startDebugServer(int serverport);
    /// 关闭调试服务器
    void closeDebugServer(void);
    /// 检测是否启动调试服务器
    bool isstardedDebugServer(void);

    /// 开始执行脚本
    void runScript(void);
    /// 注册一个新的对象
    QScriptValue RegisterNewObject(QString objName,QObject *newobject,bool isCppOwnership=false);
    /// 发送日志信息
    Q_INVOKABLE void Log(QString msg, QString type="info",
                         bool isuseGBK=true,
                         bool isPrint=true,bool isSend=true,
                         bool isLog=true,bool isProg=false);

    /// 设置当前工作目录
    inline void attachCurrentWorkingPath(QString path,bool isCurrentpath=false);
    /// 得到当前工作目录
    inline QString getCurrentWorkingPath(void) { return m_currentWorkingPath; }
    /// 设置当前系统插件目录
    inline void setRegDllPath(QString path) { m_regDllPath = path; }
    /// 得到当前系统插件目录
    inline QString getRegDllPath(void) { return m_regDllPath; }
    /// 设置调试服务器的端口
    inline void setDebugServerPort(int port) { m_debugServerPort = port; }
    /// 得到调试服务器的端口
    inline int getDebugServerPort(void) { return m_debugServerPort; }
    /// 设置是否启动自动导入脚本
    inline void setAutoloadScript(bool isEnable) { m_isautoloadscript = isEnable; }
    /// 是否启动自动导入脚本
    inline bool isAutoloadScript(void) { return m_isautoloadscript; }
    /// 设置是否启动调试服务器
    inline void setStartDebugServer(bool isEnable) { m_isStartDebugServer = isEnable; }
    /// 是否启动调试服务器
    inline bool isStartDebugServer(void) { return m_isStartDebugServer; }
    /// 设置是否开启调试模式
    inline void setEnableDebugMode(bool isEnable) { m_isEnableDebugMode = isEnable; }
    /// 是否开启调试模式
    inline bool isEnableDebugMode(void) { return m_isEnableDebugMode; }

signals:
    /// 处理日志消息
    void on_signalLog(QString msg,QString type);
    /// 脚本初始化
    void on_signalsystemsetup(void);

public slots:
    void WorkingdirectoryChange(const QString &path);
    void WorkingdirectoryChanged(void);

private:
    /// 清除所有的插件
    void cleanallplugin(void);
    /// 注册所有用到的函数
    void reg_all2jss(void);
    /// 监控指定目录下所有的文件
    void Monitoringdirectory(void);
    /// 从指定文件中导入脚本并执行
    bool js_loadscriptstring_callback(QString scriptfilepath,bool isCheckMd5=true);
    /// 初始脚本系统
    void js_setup_callback(void);

protected:
    /// 处理网络字符串消息
    virtual void OnProcessNetText(QWebSocket *conn,QString mes);
    /// 处理网络二进制消息
    virtual void OnProcessNetBinary(QWebSocket *conn,QByteArray &data);
    /// 处理一个新的连接到达
    virtual void OnProcessConnectedNetMes(QWebSocket *conn);
    /// 处理一个连接关闭
    virtual void OnProcessDisconnectedNetMes(QWebSocket *conn);
    /// 处理二进制文件发送，接收进度，type:0发送，1接收
    virtual void OnProcessBinaryOperProcess(QWebSocket *conn,int type,qint64 sendsize,qint64 totalsize);

private:
    QScriptEngine m_ScriptEngine;                                 /**< 脚本引擎 */
    QScriptEngineDebugger m_ScriptEngineDebugger;                 /**< 脚本引擎调试器 */
    CWebSocketServer m_WebSocketServer;                           /**< 网络支持 */
    QFileSystemWatcher m_pSystemWorkingPathWatcher;               /**< 用于监控系统工作目录以便于重新加载脚本 */
    QTimer m_SystemWorkingPathTimer;                              /**< 用于过滤工作目录不停改变的情况,我们只需要最后的改变 */
    bool m_isautoloadscript;                                      /**< 脚本改变后是否自动重载脚本 */
    bool m_isStartDebugServer;                                    /**< 是否启动调试服务器 */
    bool m_isEnableDebugMode;                                     /**< 是否开启调试模式 */
    QString m_currentWorkingPath;                                 /**< 当前系统工作目录 */
    QString m_regDllPath;                                         /**< 当前系统注册插件的目录 */
    int m_debugServerPort;                                        /**< 调试服务器的端口 */
    QVector<QString> m_allResourcesPath;                          /**< 所有的资源工作路径 */
    QHash<QString,tagpluginItem*> m_LibraryList;                  /**< 所有注册的插件 */
    QString m_currentScriptMd5;                                   /**< 当前脚本的md5码 */
};

#endif // CJSMANAGER2_H
